<!--
 * @Descripttion: 表格组件封装，基于vxe-table@2.9.16、vxe-table-plugin-element@1.9.1、xe-utils@2.7.5
 * @version: V2.0
 * @Author: 34786
 * @Date: 2020-08-10 17:10:52
 * @LastEditors: 34786
 * @LastEditTime: 2021-07-12 16:54:36
-->

<script>
//文档地址: https://xuliangzhan_admin.gitee.io/vxe-table/v2/index.html#/table/api
//github地址: https://github.com/xuliangzhan/vxe-table
// import request from "@/common/api/request";
import { renderColHandler, renderPaginationHandler } from "./js/renderHandler";
import methods from "./mixinx/methods";
export default {
  name: "commonTable",
  mixins: [methods],
  props: {
    canCtrlEditable: {
      type: Boolean,
      default: false
    },
    canMergeCells: {
      type: Boolean,
      default: false
    },
    canCtrlCheck: {
      type: Boolean,
      default: false
    },
    customValidRules: Object,
    canEditMethod: [Function],
    editDisabledMethod: [Function],
    propsMergeCellsMethod: [Function],
    propsFooterMethod: [Function],
    propsFooterCellClass: [Function],
    propsCheckMethod: [Function]
  },
  data() {
    return {
      tableData: [],
      tableColumns: [],
      opt: {
        url: "",
        param: {},
        params: { name: "", pageSize: 10, pageNumber: 1 }
      },
      hasPage: true,
      loading: false,
      isLocalData: false,
      tableTotalList: null,
      selectType: "",
      tableOptDef: {
        align: "left",
        headerAlign: "left",
        footerAlign: "left",
        highlightCurrentRow: true,
        highlightHoverRow: true,
        seqConfig: {
          seqMethod: this.seqMethod
        },
        radioConfig: {
          checkMethod: this.checkMethod
        },
        checkboxConfig: {
          checkMethod: this.checkMethod
        },
        editConfig: {
          activeMethod: this.activeEditMethod
        },
        editRules: this.customValidRules,
        spanMethod: this.mergeCellsMethod,
        footerMethod: this.footerMethod,
        footerCellClassName: this.footerCellClassName
      },
      tableEvents: {},
      columnOptDef: {
        minWidth: "80px"
      },
      pageOptDef: {
        currentPage: 0,
        pageCount: 0,
        total: 0,
        origPageSize: 10 // 记录原始 pageSize
      },
      miniPageDef: {
        size: "mini",
        layouts: ["PrevPage", "Jump", "PageCount", "NextPage", "Sizes", "Total"]
      }
    };
  },
  mounted() {
    // TODO 设置默认 pageSize
    let { pageSize } = this.$refs.pagination;
    this.pageOptDef["pageSize"] = pageSize;
    this.pageOptDef["origPageSize"] = pageSize;
  },
  methods: {
    /**
     * @name: load
     * @description: 加载数据
     * @type: Function
     * @param {type}
     * @return {Promise}
     */
    load(url, param, pageNo, rowNum) {
      return new Promise((resolve, reject) => {
        this.isLocalData = false;
        let page_url = url;
        this.opt.url = page_url;
        if (!page_url.includes("?")) {
          page_url = page_url + "?";
        } else {
          page_url = page_url + "&";
        }
        if (pageNo) {
          this.opt.params.pageNumber = pageNo;
          page_url = page_url + "pageNumber=" + pageNo;
        } else {
          page_url = page_url + "pageNumber=1";
        }
        let pageSize = 0;
        if (this.hasPage) {
          if (rowNum) {
            this.opt.params.pageSize = rowNum;
          }
          pageSize = this.opt.params.pageSize;
        }
        page_url = page_url + "&pageSize=" + pageSize;
        this.opt.param = param;
        this.getTableRowsData(page_url, this.opt.param, resolve, reject);
      });
    },
    //获取表格数据
    getTableRowsData(url, param, resolve, reject) {
      this.loading = true;
      request({
        method: "post",
        url: url,
        data: param,
        hideLoading: true
      })
        .then(res => {
          if (res && res.list) {
            this.tableData = res.list; // 列表数据
            this.pageOptDef.pageCount = res.pages; //总页数
            this.pageOptDef.pageSize = res.pageSize; //每页几条
            this.pageOptDef.total = res.total; //总条数
            this.pageOptDef.currentPage = res.pageNum; // 当前页
          } else {
            this.tableData = [];
            this.pageOptDef.pageCount = 1; //总页数
            this.pageOptDef.pageSize = this.pageOptDef.origPageSize; //每页几条
            this.pageOptDef.total = 0; //总条数
            this.pageOptDef.currentPage = 1; // 当前页
          }
          this.loading = false;
          resolve(this.tableData);
        })
        .catch(err => {
          this.loading = false;
          reject(err);
        });
    },

    /**
     * @name: loadLocalData
     * @description: 渲染非 load 方法获取的数据，目前不支持 排序、筛选 等功能
     * @type: Function
     * @param {object | array} data: 渲染表格的数据，外部调用传入 Object {list: [...]}
     * @return {Promise}
     */
    loadLocalData(data = []) {
      return new Promise((resolve, reject) => {
        this.isLocalData = true;
        if (Array.isArray(data)) {
          this.tableData = data;
        } else {
          if (this.hasPage) {
            this.tableTotalList = data.list; // 保留总数据
            this.pageOptDef.currentPage = 1; // 当前页
            this.pageOptDef.total = data.list.length; // 总条数
            this.pageOptDef.pageCount =
              data.list.length % this.pageOptDef.pageSize == 0
                ? data.list.length / this.pageOptDef.pageSize
                : Math.floor(data.list.length / this.pageOptDef.pageSize) + 1; // 总页数

            this.tableData = data.list.slice(0, this.pageOptDef.pageSize);
          } else {
            this.tableData = data.list;
          }
        }
        resolve();
      });
    },

    /**
     * @name: SetColumn
     * @description: 初始化表格列
     * @param {array} column: 列配置项
     * @param {object} tableOpt: 表格设置配置项
     */
    SetColumn(column = [], tableOpt = {}) {
      this.tableColumns = []; // 列数据置空
      let { page, pageType, pageConfig, events, showIndex } = tableOpt;
      if (page === false) {
        this.hasPage = false;
      }
      // 简易分页器的快捷配置
      if (pageType == "mini" || (pageConfig && pageConfig.small)) {
        // pageType == "mini" 为了兼容上个版本的封装
        Object.assign(this.pageOptDef, this.miniPageDef, pageConfig);
      }
      // 翻页器自定义配置
      if (pageConfig && !pageConfig.small) {
        Object.assign(this.pageOptDef, pageConfig);
        if (pageConfig.pageSize) {
          this.pageOptDef.origPageSize = pageConfig.pageSize;
        }
      }
      if (events) {
        Object.assign(this.tableEvents, events);
      }
      if (showIndex) {
        // 为了兼容上个版本的封装
        column.unshift({ type: "seq", width: "50", fixed: "left" });
      }
      Object.defineProperty(tableOpt, "page", { enumerable: false });
      Object.defineProperty(tableOpt, "pageType", { enumerable: false });
      Object.defineProperty(tableOpt, "pageConfig", { enumerable: false });
      Object.defineProperty(tableOpt, "events", { enumerable: false });

      Object.assign(this.tableOptDef, tableOpt);
      column.forEach(item => {
        if (item.type && item.type == "selection") {
          item.type = "checkbox"; // 兼容[vxe-table]老版本
        }
        const column = Object.assign({}, this.columnOptDef, item);
        this.tableColumns.push(column);
      });
      this._getSelectType(this.tableColumns);
      setTimeout(() => {
        this._scaleTable();
      }, 0);
    },
    // vxe-pager 事件
    pagerChange({ type, currentPage, pageSize, $event }) {
      if (type == "current") {
        // 翻页
        this.TablePagingFn(currentPage, pageSize);
      } else if (type == "size") {
        // 改变每页显示条目
        this.pageSizeChangeFn(pageSize);
      }
    },
    //分页事件
    TablePagingFn(pagingIndex, pageSize) {
      if (this.isLocalData) {
        // 本地分页
        this.pageOptDef.currentPage = pagingIndex;
        this.pageOptDef.pageSize = pageSize;
        let st = (pagingIndex - 1) * pageSize;
        let en = st + (pageSize - 0);
        let temp = this.tableTotalList.slice(st, en);
        this.loadLocalData(temp);
      } else {
        let opt = this.opt;
        opt.params.pageNumber = pagingIndex;
        //改变页数，请求数据
        this.load(opt.url, opt.param, pagingIndex);
      }
    },
    // 改变每页展示条数回调事件
    pageSizeChangeFn(val) {
      if (this.isLocalData) {
        // 本地分页
        this.pageOptDef.pageSize = val;
        this.pageOptDef.currentPage = 1;
        let st = 0;
        let en = val;
        this.pageOptDef.pageCount =
          this.tableTotalList.length % this.pageOptDef.pageSize == 0
            ? this.tableTotalList.length / this.pageOptDef.pageSize
            : Math.floor(
                this.tableTotalList.length / this.pageOptDef.pageSize
              ) + 1;
        let temp = this.tableTotalList.slice(st, en);
        this.loadLocalData(temp);
      } else {
        this.pageOptDef.pageSize = val;
        let opt = this.opt;
        opt.params.pageSize = val;
        opt.params.pageNumber = 1;
        this.load(opt.url, opt.param, 1, val);
      }
    },

    /* --------------------- Events ---------------------- */

    // 行选择触发
    rowSelectCbk({
      records,
      reserves,
      indeterminates,
      checked,
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
      $event
    }) {
      // TODO: 验证 records, reserves, indeterminates 是什么
      this.$emit("selectsEvent", {
        reserves,
        row: row,
        rowIndex,
        $rowIndex,
        column,
        columnIndex,
        $columnIndex,
        selection: records,
        checked: checked
      });
    },
    // 全选触发
    selectAllCbk({ records, reserves, indeterminates, checked, $event }) {
      this.$emit("checkboxAll", {
        records,
        reserves,
        indeterminates,
        checked,
        $event
      });
    },
    // 单元格单击触发
    handleCellClick({
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
      triggerRadio,
      triggerCheckbox,
      $event
    }) {
      // TODO: 这里和之前返回的参数形式不同
      this.$emit("handleCellClick", {
        row,
        rowIndex,
        $rowIndex,
        column,
        columnIndex,
        $columnIndex,
        triggerRadio,
        triggerCheckbox,
        $event
      });
    },
    // 单元格双击触发
    handleCellDbClick({
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
      $event
    }) {
      this.$emit("handleCellDbClick", {
        row,
        rowIndex,
        $rowIndex,
        column,
        columnIndex,
        $columnIndex,
        $event
      });
    },
    // 单元格编辑状态被关闭时触发
    editClosedCbk({
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex
    }) {
      // 如果启用了表尾合计，单元格编辑失去焦点后更新表尾合计
      if (this.tableOptDef.showFooter) {
        this.$refs.editable.updateFooter();
      }
      this.$emit("handleBlurActive", {
        row,
        rowIndex,
        $rowIndex,
        column,
        columnIndex,
        $columnIndex
      });
    },
    // 是否允许编辑(行或者单元格),配合 editDisabledEvent 使用, 必须 prop 传入 canCtrlEditable
    activeEditMethod({ row, rowIndex, column, columnIndex }) {
      if (this.canCtrlEditable) {
        return this.canEditMethod({ row, rowIndex, column, columnIndex });
      } else {
        return true;
      }
    },
    // 不允许编辑的处理方法, 配合 activeEditMethod 使用, 必须 prop 传入 canCtrlEditable
    editDisabledEvent({ row, rowIndex, column, columnIndex }) {
      if (this.canCtrlEditable) {
        this.editDisabledMethod({ row, rowIndex, column, columnIndex });
      }
    },
    // 序号规则默认方法
    seqMethod({ $rowIndex, seq }) {
      if (this.hasPage) {
        const temp =
          (this.pageOptDef.currentPage - 1) * this.pageOptDef.pageSize;
        return temp + $rowIndex + 1;
      } else {
        return seq;
      }
    },
    // 是否可被选，配合 canCtrlCheck 使用
    checkMethod({ row }) {
      if (this.canCtrlCheck) {
        return this.propsCheckMethod({ row });
      } else {
        return true;
      }
    },
    // 排序触发
    sortChange({ column, property, order, $event }) {
      if (column.remoteSort === false) {
        // 当前列关闭了远程排序，前端排序
      } else {
        // 当前字段 property;  从小到大 order == "asc" 从大到小的 order == "desc" 没有时 null
        let name = property;
        name = name.replace(/([A-Z])/g, "_$1").toLowerCase();
        if (this.opt.url.includes("?")) {
          var index = this.opt.url.lastIndexOf("?");
          if (order != null) {
            this.opt.url =
              this.opt.url.substring(0, index) +
              "?orderBy=" +
              name +
              " " +
              order;
          } else {
            this.opt.url = this.opt.url.substring(0, index);
          }
        } else {
          if (order != null) {
            this.opt.url = this.opt.url + "?orderBy=" + name + " " + order;
          }
        }
        this.load(
          this.opt.url,
          this.opt.param,
          this.opt.params.pageNumber,
          this.opt.params.pageSize
        );
      }
    },
    // 筛选触发
    filterChange({ column, property, values, datas, filters, $event }) {
      // 筛选默认 非服务端
      if (
        this.tableOptDef.filterConfig &&
        this.tableOptDef.filterConfig.remote
      ) {
        // 开启远程筛选
        alert("启用服务端排序，尚未沟通传参方式");
      } else {
        // 前端筛选
      }
    },
    // 行、列 单元格合并，配合 canMergeCells 使用
    mergeCellsMethod({
      row,
      $rowIndex,
      rowIndex,
      column,
      $columnIndex,
      columnIndex,
      data
    }) {
      if (this.canMergeCells) {
        return this.propsMergeCellsMethod({
          row,
          $rowIndex,
          rowIndex,
          column,
          $columnIndex,
          columnIndex,
          data
        });
      }
    },
    // 表尾合计, 使用时初始化表格时配置 showFooter: true
    footerMethod({ columns, data }) {
      return this.propsFooterMethod({ columns, data });
    },
    footerCellClassName({ $rowIndex, column, columnIndex }) {
      return this.propsFooterCellClass({ $rowIndex, column, columnIndex });
    },

    /* --------------------- Methods ---------------------- */

    // 内部使用方法，判断 单选还是多选
    _getSelectType(columns) {
      const len = columns.length;
      for (let i = 0; i < len; i++) {
        let column = columns[i];
        if (column.type && column.type == "radio") {
          this.selectType = "radio";
          return;
        } else if (
          column.type &&
          (column.type == "selection" || column.type == "checkbox")
        ) {
          this.selectType = "checkbox";
          return;
        }
      }
    },
    // 内部使用方法，缩放表格
    _scaleTable() {
      // TODO: print
      const editTableWrap = this.$refs.editable.$parent.$el;
      const innerTable = this.$refs.editable.$el;
      const innerTableBody = innerTable.getElementsByClassName(
        "vxe-table--body"
      )[0];
      if (this.$route.query["activePrint"]) {
        const innerTableW = innerTableBody.offsetWidth; //表格实际内容宽度
        const editTableWrapW = editTableWrap.offsetWidth; //表格wrap的宽度
        const table = this.$refs.editable.$el;
        table.style.width = innerTableW + "px";
        let scale = editTableWrapW / innerTableW;
        scale = scale < 1 ? scale : 1;
        table.style.transform = `scaleX(${scale})`;
        table.style.transformOrigin = "0 0";
        console.log(
          "wrap宽度" + editTableWrapW + "innertable宽度" + innerTableW
        );
      }
    }
  },
  render(h) {
    return h("div", { class: "editable-wrap" }, [
      h(
        "vxe-table",
        {
          props: {
            data: this.tableData,
            loading: this.loading,
            ...this.tableOptDef
          },
          on: {
            "current-change": this.rowSelectCbk,
            "radio-change": this.rowSelectCbk,
            "checkbox-change": this.rowSelectCbk,
            "checkbox-all": this.selectAllCbk,
            "cell-click": this.handleCellClick,
            "cell-dblclick": this.handleCellDbClick,
            "edit-closed": this.editClosedCbk,
            "edit-disabled": this.editDisabledEvent,
            "sort-change": this.sortChange,
            "filter-change": this.filterChange,
            ...this.tableEvents
          },
          scopedSlots: {
            empty: () => {
              return (
                <span style={"color: #999;font-size: 14px;"}>
                  {this.$i18n.t("appCommon.noData")}
                </span>
              );
            }
          },
          ref: "editable"
        },
        renderColHandler(h, this.tableColumns)
      ),
      renderPaginationHandler(
        h,
        this.pageOptDef,
        this.hasPage,
        this.pagerChange
      )
    ]);
  }
};
</script>
<style lang="scss" scoped></style>
